
#include "CurLrn.h"

int main(int argc, const char* argv[])
{
	int nRetCode = 0;
	CMyRandom::InitRandomSeed();
	CImageEx::Initialize();

	if (1)
	{
		string strFN_Configuration		=	argv[1];
		string strOperation				=	argv[2];

		strOperation += "00000000";
		int Op_MakeCrop_GT_List			=	CDataStructureTools::Hex2Num(strOperation[0]);
		int Op_MakeBicExampleList		=	CDataStructureTools::Hex2Num(strOperation[1]);
		int Op_BoostTrainTest			=	CDataStructureTools::Hex2Num(strOperation[2]);
		int Op_BoostDetect				=	CDataStructureTools::Hex2Num(strOperation[3]);
		int Op_BoostAnalyse				=	CDataStructureTools::Hex2Num(strOperation[4]);

		char strTemp[10001] = "";
		int sgnImageSet, sgnPosNeg, i_image, i_example, i_layer;
		sgnImageSet = sgnPosNeg = i_image = i_example = i_layer = 0;

		//////////	Config Loading	//////////

		CConfiguration Config(strFN_Configuration);
		Config.Load();

		string strFN_OutLog =
			Config.GetString("strFN_OutLog", "global.log");

		// Initialize SrcImage Set
		EnvVar.sil_Train_Pos.myInit(
			02,
			Config.GetString("strPN_sil_Image_Train_Pos"),
			Config.GetInt("Amount_sil_Image_Train_Pos"),
			Config.GetString("strPN_sil_Annotation_Train_Pos"),
			Config.GetString("strFN_sil_LabelList_Train_Pos"));
		EnvVar.sil_Train_Neg.myInit(
			00,
			Config.GetString("strPN_sil_Image_Train_Neg"),
			Config.GetInt("Amount_sil_Image_Train_Neg"),
			"", "");
		EnvVar.sil_Test_Pos.myInit(
			12,
			Config.GetString("strPN_sil_Image_Test_Pos"),
			Config.GetInt("Amount_sil_Image_Test_Pos"),
			Config.GetString("strPN_sil_Annotation_Test_Pos"),
			Config.GetString("strFN_sil_LabelList_Test_Pos"));
		EnvVar.sil_Test_Neg.myInit(
			10,
			Config.GetString("strPN_sil_Image_Test_Neg"),
			Config.GetInt("Amount_sil_Image_Test_Neg"),
			"", "");

		EnvVar.strPN_Base_ExampleSet =
			Config.GetString("strPN_Base_ExampleSet");
		EnvVar.strPN_sil_Image_CropGT_Train =
			Config.GetString("strPN_sil_Image_CropGT_Train");
		EnvVar.strPN_sil_Image_CropGT_Test =
			Config.GetString("strPN_sil_Image_CropGT_Test");
		EnvVar.strFN_Amount_CropGT_Train =
			Config.GetString("strFN_Amount_CropGT_Train");
		EnvVar.strFN_Amount_CropGT_Test =
			Config.GetString("strFN_Amount_CropGT_Test");
		EnvVar.strFN_BicExampleList_Train =
			Config.GetString("strFN_BicExampleList_Train");
		EnvVar.strFN_BicExampleList_Test =
			Config.GetString("strFN_BicExampleList_Test");

		// Temporary Initialize CropGT Set
		EnvVar.sil_Train_CropGT.myInit(
			01,
			EnvVar.GetPN_sil_Image_CropGT(0),
			0, "", "");
		EnvVar.sil_Test_CropGT.myInit(
			11,
			EnvVar.GetPN_sil_Image_CropGT(1),
			0, "", "");
		EnvVar.pfsl_Train.Clear();
		EnvVar.pfsl_Test.Clear();

		EnvVar.cgtss_Train.myInit(
			Config.GetInt("IdealAmount_CropGT_Train"),
			Config.GetDouble("IdealRatio_CropGT_Train_Easy"),
			Config.GetDouble("IdealRatio_CropGT_Train_Hard"),
			Config.GetDouble("IdealRatio_CropGT_Train_Unknown"));
		EnvVar.cgtss_Test.myInit(
			Config.GetInt("IdealAmount_CropGT_Test"),
			Config.GetDouble("IdealRatio_CropGT_Test_Easy"),
			Config.GetDouble("IdealRatio_CropGT_Test_Hard"),
			Config.GetDouble("IdealRatio_CropGT_Test_Unknown"));

		int ForTrain_PosExampleShakeAmount =
			Config.GetInt("ForTrain_PosExampleShakeAmount");

		CBicExampleConfig BicEC;
		BicEC.SetPosExampleBasicConfiguration(
			Config.GetInt("CropGT_ImageExtent"),
			Config.GetDouble("CropGT_ImageScale"),
			Config.GetDouble("CropGT_ImageScale"));
		BicEC.SetPosExampleShakingConfiguration(
			Config.GetDouble("CropGT_ShakeRange_xCenter"),
			Config.GetDouble("CropGT_ShakeRange_yCenter"),
			Config.GetDouble("CropGT_ShakeRange_xScale"),
			Config.GetDouble("CropGT_ShakeRange_yScale"));
		BicEC.SetScanningFitBoxConfiguration(CBicExampleConfig::FIT_BOX_STYLE_TIGHT, 32, 32);
		BicEC.SetStdObjectTightConfiguration(
			Config.GetInt("CropGT_StdTight_W"),
			Config.GetInt("CropGT_StdTight_H"),
			Config.GetDouble("CropGT_StdTight_xTolerance"),
			Config.GetDouble("CropGT_StdTight_yTolerance"));
		BicEC.SetStdObjectContextConfiguration(
			Config.GetInt("CropGT_StdContext_W"),
			Config.GetInt("CropGT_StdContext_H"),
			Config.GetDouble("CropGT_StdContext_xCenter"),
			Config.GetDouble("CropGT_StdContext_yCenter"));

		int Scan_PixelSampleMargin_Train =
			Config.GetInt("Scan_PixelSampleMargin_Train");
		double Scan_PixelSampleRate_Train =
			Config.GetDouble("Scan_PixelSampleRate_Train");
		double Scan_ScalingFactor_Train =
			Config.GetDouble("Scan_ScalingFactor_Train");
		int Scan_PixelSampleMargin_Test =
			Config.GetInt("Scan_PixelSampleMargin_Test");
		double Scan_PixelSampleRate_Test =
			Config.GetDouble("Scan_PixelSampleRate_Test");
		double Scan_ScalingFactor_Test =
			Config.GetDouble("Scan_ScalingFactor_Test");

		EnvVar.strPN_Base_BoostModel =
			Config.GetString("strPN_Base_BoostModel");
		EnvVar.strFN_BoostModel =
			Config.GetString("strFN_BoostModel");
		EnvVar.strFN_BoostTrainLog =
			Config.GetString("strFN_BoostTrainLog");
		EnvVar.strFN_BoostTestROC =
			Config.GetString("strFN_BoostTestROC");

		// Setup Feature Component
		CFeatureExtractor FeatureExtractor;
		{
			FeatureExtractor.IFB_ImageExtent = 16;
			FeatureExtractor.IFB_TextonSigma = 0.7;
			FeatureExtractor.InitIFB();
			FeatureExtractor.SPL_HOG_Win_W = BicEC.StdObjectContext_W;
			FeatureExtractor.SPL_HOG_Win_H = BicEC.StdObjectContext_H;
			FeatureExtractor.SPL_HOG_Blk_BaseW = 16.0;
			FeatureExtractor.SPL_HOG_Blk_BaseH = 16.0;
			FeatureExtractor.SPL_HOG_Blk_BaseStrideX = 8.0;
			FeatureExtractor.SPL_HOG_Blk_BaseStrideY = 8.0;
			FeatureExtractor.SPL_HOG_Blk_ScalingFactor = 2.0;
			FeatureExtractor.InitShapePatternLists();
		} // Setup Feature Component

		// Setup Boost Configuration
		CCascadedAdaBoostParametersConfig CascadeConfig;
		int CascadeBoost_TrainingMemoryUsage_MB =
			Config.GetInt("CascadeBoost_TrainingMemoryUsage_MB");
		int CascadeBoost_StartingLayerIndex =
			Config.GetInt("CascadeBoost_StartingLayerIndex");
		{
			// Main Settings
			CascadeConfig.MaxLayerAmount =
				Config.GetInt("CascadeBoost_LayerAmount");
			CascadeConfig.InitLayerTrainingEndConditionList(
				Config.GetString("CascadeBoost_strFN_PerLayerCondition"));
			CascadeConfig.MaxTrainPosExampleAmount =
				Config.GetInt("CascadeBoost_TrainLayer_MaxPosAmount");
			CascadeConfig.MinTrainPosExampleAmount =
				Config.GetInt("CascadeBoost_TrainLayer_MinPosAmount");
			CascadeConfig.MaxTrainNegExampleAmount =
				Config.GetInt("CascadeBoost_TrainLayer_MaxNegAmount");
			CascadeConfig.MinTrainNegExampleAmount =
				Config.GetInt("CascadeBoost_TrainLayer_MinNegAmount");
			// Memory Settings
			CascadeConfig.FeatureMemoryUsage_Pos_Train = CascadeBoost_TrainingMemoryUsage_MB * 2 / 9;
			CascadeConfig.FeatureMemoryUsage_Pos_Val = CascadeBoost_TrainingMemoryUsage_MB * 1 / 9;
			CascadeConfig.FeatureMemoryUsage_Train = CascadeBoost_TrainingMemoryUsage_MB * 4 / 9;
			CascadeConfig.FeatureMemoryUsage_Val = CascadeBoost_TrainingMemoryUsage_MB * 2 / 9;
			// Following settings are not most important
			CascadeConfig.strPN_ForTrain = EnvVar.strPN_Base_BoostModel;
			CascadeConfig.AdaBoostConfig.SFC_BinAmount = 1000;
			
			CascadeConfig.AdaBoostConfig.fDetermineLayerThresholdUsingValSet =(
				Config.GetInt("CasecadeBoost_UseValSetForTraining", 0) == 1);
			//CascadeConfig.AdaBoostConfig.fDetermineLayerThresholdUsingValSet = false;
			
			CascadeConfig.AdaBoostConfig.SFC_FeatureSampleRate = 0.10;
			CascadeConfig.AdaBoostConfig.DataSetUpdatingFrequency = 200;
			CascadeConfig.TrainFeatureGroupAmount = 20;
			CascadeConfig.OutputROC_SamplingCount = 120;
			CascadeConfig.OutputROC_MinFPR = 1e-6;
			CascadeConfig.OutputROC_MaxFPR = 1e-0;
			CascadeConfig.OutputROC_fUseLogScale = true;
		} // Setup Boost Configuration

		// Setup Boost Detecting Configuration
		int BoostDetect_Target_ImageSet;
		int BoostDetect_Target_PosNeg;
		{
			EnvVar.strPN_Base_BoostDetect =
				Config.GetString("strPN_Base_BoostDetect");
			EnvVar.strFN_BoostDetectPRC =
				Config.GetString("strFN_BoostDetectPRC");
			BoostDetect_Target_ImageSet =
				Config.GetInt("BoostDetect_Target_ImageSet");
			BoostDetect_Target_PosNeg = 
				Config.GetInt("BoostDetect_Target_PosNeg");
		}

		ofstream outLog(strFN_OutLog.c_str());
		CExternalTools::ConsoleTools::MakeCurrentLine("", true);
		CExternalTools::ConsoleTools::OutputTextToStream(outLog, "", true);

		// ********** Main Code Start **********
		if (1)
		{

			if (Op_MakeCrop_GT_List & 3)
			{
				CExternalTools::ConsoleTools::MakeDirectory(EnvVar.strPN_Base_ExampleSet, false);

				for ( sgnImageSet = 0; sgnImageSet < 2; ++ sgnImageSet )
				{
					if (sgnImageSet==0 && !(Op_MakeCrop_GT_List & 1)) continue;
					if (sgnImageSet==1 && !(Op_MakeCrop_GT_List & 2)) continue;

					const CNewBoostSrcImageList& src_sil = EnvVar.GetSIL_SrcImage(sgnImageSet, 1);
					const CNewBoostCropGT_SamplingSettings& src_cgtss = EnvVar.GetCGTSS_CropGT(sgnImageSet);

					const CNewBoostSrcImageList& dst_sil = EnvVar.GetSIL_CropGT(sgnImageSet);
					CExternalTools::ConsoleTools::MakeDirectory(dst_sil.strPN_SrcImage, true);

					int ta_Easy, ta_Hard, ta_Unknown;
					src_cgtss.GetTargetExampleAmount(ta_Easy, ta_Hard, ta_Unknown, src_sil);

					sprintf_s(strTemp, "\n=== Set [%s] ===", EnvVar.GetText_ImageSet(sgnImageSet));
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
					sprintf_s(strTemp, "Label # = [%d];", src_sil.Amount_GT_Total);
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
					sprintf_s(strTemp, "E/H/U Label Amount = [%d/%d/%d];",
						src_sil.Amount_GT_Easy * 2,
						src_sil.Amount_GT_Hard * 2,
						src_sil.Amount_GT_Unknown * 2);
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
					sprintf_s(strTemp, "E/H/U Sample Rate %% = [%.0lf/%.0lf/%.0lf];",
						100.0 * (ta_Easy + EPS) / (src_sil.Amount_GT_Easy * 2 + EPS),
						100.0 * (ta_Hard + EPS) / (src_sil.Amount_GT_Hard * 2 + EPS),
						100.0 * (ta_Unknown + EPS) / (src_sil.Amount_GT_Unknown * 2 + EPS));
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);

					int Amount_CropGT = 0;
					int sa_Easy = src_sil.Amount_GT_Easy * 2;
					int sa_Hard = src_sil.Amount_GT_Hard * 2;
					int sa_Unknown = src_sil.Amount_GT_Unknown * 2;
					int ra_Easy = 0;
					int ra_Hard = 0;
					int ra_Unknown = 0;
					double ttt;

					int last_image_index = -1;
					CImg<int> imgSrc;
					CImg<int> imgOutput;
					CZoomableImage ZoomImage;
					CZoomConfig ZoomConfig;
					CRectBox<double> dBox;

					int i_flip;

					for ( i_image = 0; i_image < src_sil.Amount_GT_Total; ++i_image )
					{
						const CNewBoostGroundTruthLabel& gtl = src_sil.GT_LabelList.pElement[i_image];

						for ( i_flip = 0; i_flip < 2; ++i_flip )
						{
							if (gtl.difficulty == 1)
								if (CMyRandom::NextInt(sa_Easy--) < ta_Easy - ra_Easy) ++ra_Easy; else continue;
							else if (gtl.difficulty == 2)
								if (CMyRandom::NextInt(sa_Hard--) < ta_Hard - ra_Hard) ++ra_Hard; else continue;
							else
								if (CMyRandom::NextInt(sa_Unknown--) < ta_Unknown - ra_Unknown) ++ra_Unknown; else continue;

							if (last_image_index != gtl.image_index)
							{
								last_image_index = gtl.image_index;
								CExternalTools::myLoadImage(src_sil.GetFN_SrcImage(last_image_index), imgSrc);
								ZoomImage.myInit(imgSrc);
							}
							dBox.myInit(gtl.box);
							BicEC.MakeContextBoxFromTightBox(dBox, dBox);
							int iw = (int)(0.5 + BicEC.PosExample_xScale * (BicEC.StdObjectContext_W + BicEC.PosExample_ImageExtent * 2));
							int ih = (int)(0.5 + BicEC.PosExample_yScale * (BicEC.StdObjectContext_H + BicEC.PosExample_ImageExtent * 2));

							if (i_flip == 0)
							{
								ZoomConfig.myInit(
									BicEC.PosExample_xScale * BicEC.StdObjectContext_W / dBox.w,
									BicEC.PosExample_yScale * BicEC.StdObjectContext_H / dBox.h,
									dBox.x, dBox.y,
									BicEC.PosExample_xScale * BicEC.PosExample_ImageExtent,
									BicEC.PosExample_yScale * BicEC.PosExample_ImageExtent);
							}
							else
							{
								ZoomConfig.myInit(
									-1.0 * BicEC.PosExample_xScale * BicEC.StdObjectContext_W / dBox.w,
									BicEC.PosExample_yScale * BicEC.StdObjectContext_H / dBox.h,
									dBox.x, dBox.y,
									iw - BicEC.PosExample_xScale * BicEC.PosExample_ImageExtent,
									BicEC.PosExample_yScale * BicEC.PosExample_ImageExtent);
							}

							ZoomImage.BuildImage(imgOutput, iw, ih, ZoomConfig, CDenseImage::EXPANDING_MODE_EDGE);
							CExternalTools::mySaveImage(dst_sil.GetFN_SrcImage(Amount_CropGT), imgOutput);
							++Amount_CropGT;

							sprintf_s(strTemp, "Generating CropGT [%d], Progress [%d/%d]...", 
								Amount_CropGT, i_image+1, src_sil.Amount_GT_Total);
							CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, false);
						} // i_flip
					} // i_image

					ofstream outFile(EnvVar.GetFN_Amount_CropGT(sgnImageSet).c_str());
					outFile<<Amount_CropGT<<endl;
					outFile.close();
					outFile.clear();

					ttt = ra_Easy + ra_Hard + ra_Unknown;
					sprintf_s(strTemp, "Generated CropGT # [%d], E/H/U Ratio %% = [%.0lf/%.0lf/%.0lf];",
						Amount_CropGT, 100.0*ra_Easy/ttt, 100.0*ra_Hard/ttt, 100.0*ra_Unknown/ttt);
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
				} // sgnImageSet
			} // (Op_MakeCrop_GT_List & 3)

			// Get CropGT Set
			{
				for ( sgnImageSet = 0; sgnImageSet < 2; ++ sgnImageSet )
				{
					CNewBoostSrcImageList& dst_sil = EnvVar.GetSIL_CropGT(sgnImageSet);

					int Amount_CropGT;

					ifstream inFile(EnvVar.GetFN_Amount_CropGT(sgnImageSet).c_str());
					if (!(inFile>>Amount_CropGT)) Amount_CropGT = 0;
					inFile.close();
					inFile.clear();

					dst_sil.myInit(dst_sil.BicFileNameSetIndex, dst_sil.strPN_SrcImage, Amount_CropGT, "", "");
				} // sgnImageSet

				EnvVar.pfsl_Train.Resize(3);
				EnvVar.sil_Train_Pos.MakeBicFileNameSet_SrcImage(EnvVar.pfsl_Train.pElement[0]);
				EnvVar.sil_Train_Neg.MakeBicFileNameSet_SrcImage(EnvVar.pfsl_Train.pElement[1]);
				EnvVar.sil_Train_CropGT.MakeBicFileNameSet_SrcImage(EnvVar.pfsl_Train.pElement[2]);

				EnvVar.pfsl_Test.Resize(3);
				EnvVar.sil_Test_Pos.MakeBicFileNameSet_SrcImage(EnvVar.pfsl_Test.pElement[0]);
				EnvVar.sil_Test_Neg.MakeBicFileNameSet_SrcImage(EnvVar.pfsl_Test.pElement[1]);
				EnvVar.sil_Test_CropGT.MakeBicFileNameSet_SrcImage(EnvVar.pfsl_Test.pElement[2]);
			} // Get CropGT Set

			if (Op_MakeBicExampleList & 3)
			{
				for ( sgnImageSet = 0; sgnImageSet < 2; ++ sgnImageSet )
				{
					if (sgnImageSet==0 && !(Op_MakeBicExampleList & 1)) continue;
					if (sgnImageSet==1 && !(Op_MakeBicExampleList & 2)) continue;

					const CNewBoostSrcImageList& src_sil_Pos = EnvVar.GetSIL_CropGT(sgnImageSet);
					const CNewBoostSrcImageList& src_sil_Neg = EnvVar.GetSIL_SrcImage(sgnImageSet, 0);

					CBicExample be;
					CSimpleTypeArray<CBicExample> BicExampleList;
					BicExampleList.Clear();

					sprintf_s(strTemp, "\n=== Set [%s] ===", EnvVar.GetText_ImageSet(sgnImageSet));
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);

					for ( i_image = 0; i_image < src_sil_Pos.Amount_SrcImage; ++i_image )
					{
						BicEC.GeneratePosExampleList(
							BicExampleList, true, src_sil_Pos.BicFileNameSetIndex, i_image,
							(sgnImageSet==0 ? ForTrain_PosExampleShakeAmount : 1), true, true);
					} // i_image

					CImg<int> imgSrc;
					int iw, ih;
					int sAmount_NE;
					int tAmount_NE;

					for ( i_image = 0; i_image < src_sil_Neg.Amount_SrcImage; ++i_image )
					{
						CExternalTools::myLoadImage(src_sil_Neg.GetFN_SrcImage(i_image), imgSrc);
						iw = imgSrc.width; ih = imgSrc.height;

						sAmount_NE = 0;
						for ( i_layer = 0; ; ++i_layer )
						{
							tAmount_NE = BicEC.GenerateNegExampleList(BicExampleList, true, iw, ih,
								Scan_PixelSampleMargin_Train, Scan_PixelSampleRate_Train, i_layer, Scan_ScalingFactor_Train,
								src_sil_Neg.BicFileNameSetIndex, i_image);
							if (tAmount_NE < 1) break;
							sAmount_NE += tAmount_NE;
						}

						if (i_image==src_sil_Neg.Amount_SrcImage-1 || CMyRandom::NextInt(src_sil_Neg.Amount_SrcImage/100)==0)
						{
							sprintf_s(strTemp, "Neg Image [%d/%d], Layer # [%d], c/t BE # = [%.1lfK/%.2lfM];",
								i_image+1, src_sil_Neg.Amount_SrcImage,
								i_layer, sAmount_NE/1000.0, BicExampleList.Size/1000000.0);
							CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, false);
							//if (i_image==src_sil_Neg.Amount_SrcImage-1)
							//	CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, false);
						}
					} // i_image
					//cout<<endl; outLog<<endl;

					//CBicExample::OutputListToFile(EnvVar.GetFN_BicExampleList(sgnImageSet), BicExampleList);
					CBicExample::OutputListToBinaryFile(EnvVar.GetFN_BicExampleList(sgnImageSet), BicExampleList);
					//CBicExample::InputListFromBinaryFile(BicExampleList, EnvVar.GetFN_BicExampleList(sgnImageSet))<<endl;

					sprintf_s(strTemp, "Generated Bic Example List, BE # = [%.2lfM];",
						BicExampleList.Size/1000000.0);
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
				} // sgnImageSet
			} // (Op_MakeBicExampleList & 3)

			if (Op_BoostTrainTest & 1)
			{
				CExternalTools::ConsoleTools::MakeDirectory(EnvVar.strPN_Base_BoostModel);

				CImagePyramidPositionFeatureExtractor* pIPPFE = FeatureExtractor.GetIPPFE(1);

				CBicExampleFeatureDataSet DataSet_Train;
				CDataSetForBinaryClassification bds_Train;
				CBinaryClassificationExampleList ExampleList_Train;

				sgnImageSet = 0;
				DataSet_Train.InitBicExampleParentFileNameSetList(&EnvVar.pfsl_Train, "FOR_TRAIN.");
				DataSet_Train.InitBicExampleList_Binary(EnvVar.GetFN_BicExampleList(sgnImageSet));
				DataSet_Train.InitIPPFE(pIPPFE, false);
				bds_Train.SetRealDataSet(&DataSet_Train);
				bds_Train.SetTargetLabel(+1);
				ExampleList_Train.myInit(&bds_Train);

				CBicExampleFeatureDataSet DataSet_Test;
				CDataSetForBinaryClassification bds_Test;
				CBinaryClassificationExampleList ExampleList_Test;

				sgnImageSet = 1;
				DataSet_Test.InitBicExampleParentFileNameSetList(&EnvVar.pfsl_Test, "FOR_TRAIN.");
				DataSet_Test.InitBicExampleList_Binary(EnvVar.GetFN_BicExampleList(sgnImageSet));
				DataSet_Test.InitIPPFE(pIPPFE, true);
				bds_Test.SetRealDataSet(&DataSet_Test);
				bds_Test.SetTargetLabel(+1);
				ExampleList_Test.myInit(&bds_Test);

				int i;
				for ( i = 0; i < ExampleList_Train.PosList.ExampleAmount; ++i ) ExampleList_Train.PosList.rgExample[i].Weight = 1.0; // 1.0 / ExampleList_Train.PosList.ExampleAmount;
				for ( i = 0; i < ExampleList_Train.NegList.ExampleAmount; ++i ) ExampleList_Train.NegList.rgExample[i].Weight = 1.0; // 1e4 / ExampleList_Train.NegList.ExampleAmount; // 1.0;
				ExampleList_Train.NormalizeExampleWeight();
				for ( i = 0; i < ExampleList_Test.PosList.ExampleAmount; ++i ) ExampleList_Test.PosList.rgExample[i].Weight = 1.0; // 1.0 / ExampleList_Test.PosList.ExampleAmount;
				for ( i = 0; i < ExampleList_Test.NegList.ExampleAmount; ++i ) ExampleList_Test.NegList.rgExample[i].Weight = 1.0; // 1e4 / ExampleList_Test.NegList.ExampleAmount; // 1.0;
				ExampleList_Test.NormalizeExampleWeight();

				system("cls");
				ofstream outTrainLog(EnvVar.GetFN_BoostTrainLog().c_str());
				CCascadedAdaBoostClassifier cabc;
				string strFN_BoostModel = EnvVar.GetFN_BoostModel();
				cabc.LoadFromFile(strFN_BoostModel);
				cabc.Train(
					strFN_BoostModel, CascadeBoost_StartingLayerIndex, 0,
					&bds_Train, ExampleList_Train,
					&bds_Test, ExampleList_Test,
					CascadeConfig, outTrainLog);
				outTrainLog.clear();
				outTrainLog.close();

				sprintf_s(strTemp, "\nBoost Training Finished, #.WL = %d;", cabc.GetTotalWeakLearnerAmount());
				CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
				CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);

			} // (Op_BoostTrainTest & 1)

			if (Op_BoostTrainTest & 2)
			{
				CCascadedAdaBoostClassifier cabc;
				cabc.LoadFromFile(EnvVar.GetFN_BoostModel());
				CBinaryClassifier* pBinaryClassifer = &cabc;

				CImagePyramidPositionFeatureExtractor* pIPPFE = FeatureExtractor.GetIPPFE(1);

				sgnImageSet = 1;
				{
					const CNewBoostSrcImageList& sil_Pos = EnvVar.GetSIL_CropGT(sgnImageSet);
					const CNewBoostSrcImageList& sil_Neg = EnvVar.GetSIL_SrcImage(sgnImageSet, 0);

					int i_example;
					CImg<int> imgSrc;
					CBicExample tBicExample;
					CImagePyramidPosition ipp;
					double tConfidence;

					CBinaryClassificationResult_ByConfidence bcr;
					bcr.Clear();

					sprintf_s(strTemp, "\n=== Set [%s] ===", EnvVar.GetText_ImageSet(sgnImageSet));
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);

					// Pos Images
					for ( i_image = 0; i_image < sil_Pos.Amount_SrcImage; ++i_image )
					{
						CExternalTools::myLoadImage(sil_Pos.GetFN_SrcImage(i_image), imgSrc);
						pIPPFE->SetImage(imgSrc, "");

						BicEC.BuildPosExample(tBicExample, -1, -1);
						tBicExample.ToIpp(ipp);
						pIPPFE->SetQuery(ipp);

						tConfidence = pBinaryClassifer->Classify(pIPPFE);
						bcr.Pos.PushBack(tConfidence);

						sprintf_s(strTemp, "Testing Pos Set [%d/%d];", i_image+1, sil_Pos.Amount_SrcImage);
						CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, false);
						if (i_image == sil_Pos.Amount_SrcImage-1)
						{
							cout<<endl;
							CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
						}
					}
					bcr.Analyse();

					CSimpleTypeArray<CBicExample> BicExampleList;
					int sAmount_NE, tAmount_NE;

					CTimer tTimer;
					tTimer.Reset();

					// Neg Images
					for ( i_image = 0; i_image < sil_Neg.Amount_SrcImage; ++i_image )
					{
						CExternalTools::myLoadImage(sil_Neg.GetFN_SrcImage(i_image), imgSrc);
						pIPPFE->SetImage(imgSrc, "");

						BicExampleList.Clear();
						sAmount_NE = 0;
						for ( i_layer = 0; ; ++i_layer )
						{
							tAmount_NE = BicEC.GenerateNegExampleList(
								BicExampleList, true, imgSrc.width, imgSrc.height,
								Scan_PixelSampleMargin_Test, Scan_PixelSampleRate_Test, i_layer, Scan_ScalingFactor_Test,
								-1, -1);
							if (tAmount_NE < 1) break;
							sAmount_NE += tAmount_NE;
						} // i_layer

						tTimer.Start();

						for ( i_example = 0; i_example < (int)BicExampleList.Size; ++i_example )
						{
							BicExampleList.pElement[i_example].ToIpp(ipp);
							pIPPFE->SetQuery(ipp);

							tConfidence = pBinaryClassifer->Classify(pIPPFE);
							bcr.Neg.PushBack(tConfidence);
						} // i_example
						bcr.Analyse();

						tTimer.Stop();

						double TargetFPR = 1e-4;
						double MR = 1.0 - bcr.Get_Recall_By_FalsePositiveRate(TargetFPR);

						sprintf_s(strTemp, "Testing Neg Set [%d/%d], [%.1lfK/%.2lfM], MR%.0lf = %.3lf, %.2lf spi, %.2lf kwps;",
							i_image+1, sil_Neg.Amount_SrcImage,
							sAmount_NE/1000.0, bcr.Neg.Size/1000000.0,
							log(TargetFPR)/log(10.0), MR, tTimer.GetCumulativeTime()/(i_image+1), bcr.Neg.Size/tTimer.GetCumulativeTime()/1000.0);
						CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, false);
						if (i_image == sil_Neg.Amount_SrcImage-1)
						{
							cout<<endl;
							CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
						}
					} // i_image

					sprintf_s(strTemp, "Test MR-4 = %.4lf;", 1.0 - bcr.Get_Recall_By_FalsePositiveRate(1e-4));
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
					sprintf_s(strTemp, "Test MR-3 = %.4lf;", 1.0 - bcr.Get_Recall_By_FalsePositiveRate(1e-3));
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
					sprintf_s(strTemp, "Test MR-2 = %.4lf;", 1.0 - bcr.Get_Recall_By_FalsePositiveRate(1e-2));
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
					sprintf_s(strTemp, "Test MR-1 = %.4lf;", 1.0 - bcr.Get_Recall_By_FalsePositiveRate(1e-1));
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);

					ofstream outROC(EnvVar.GetFN_BoostTestROC().c_str());
					bcr.OutputROCtoStream(outROC,
						CascadeConfig.OutputROC_SamplingCount,
						CascadeConfig.OutputROC_MinFPR,
						CascadeConfig.OutputROC_MaxFPR,
						CascadeConfig.OutputROC_fUseLogScale);
					outROC.clear();
					outROC.close();

					cout<<endl;
					outLog<<endl;

				} // sgnImageSet

				CDataStructureTools::MyRelease_Single(pIPPFE);
			} // (Op_BoostTrainTest & 2)

			if (Op_BoostDetect & 1)
			{
				CExternalTools::ConsoleTools::MakeDirectory(EnvVar.strPN_Base_BoostDetect, false);

				CCascadedAdaBoostClassifier cabc;
				cabc.LoadFromFile(EnvVar.GetFN_BoostModel());
				CBinaryClassifier* pBinaryClassifer = &cabc;
				CBinaryClassificationResult_ByConfidence bcrc;
				CImagePyramidPositionFeatureExtractor* pIPPFE = FeatureExtractor.GetIPPFE(1);

				int i_example, ip_GTL, i_GT;
				CImg<int> imgSrc;
				CImg<int> imgOutput;
				CTimer tTimer;
				int count_image, _color;
				CRectBox<double> tBox;

				double OutputScale_1 = 0.5;

				// Set Target Confidence Threshold
				double Target_FPR = 1e-4;
				double Target_CT = -1e20;
				{
					ifstream inFile(EnvVar.GetFN_BoostTestROC().c_str());
					int ni;
					double t1, t2, t3, t4;
					if ((inFile>>ni>>t1>>t2) && (ni>0) && !(t1>Target_FPR) && !(t2<Target_FPR))
					{
						for ( ; ni >= 0; --ni )
						{
							inFile>>t1>>t2>>t3>>t4; // FPR, DR, CT, 1-DR
							if (t1+EPS > Target_FPR)
							{
								Target_CT = t3;
								sprintf_s(strTemp, "Boost Detect: FPR = %8.4lf%%, DR = %6.2lf%%, CT = %.6lf;", t1*100.0, t2*100.0, t3);
								CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
								CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
								break;
							}
						}
					}
					inFile.close();
					inFile.clear();
				} // Set Target Confidence Threshold

				CBicDetector::CLayerResult LayerResult;
				CBicDetector BicDetector;
				BicDetector.Init_IPPFE_and_Classifier(pIPPFE, &cabc);
				BicDetector.BicExampleConfig = BicEC;
				BicDetector.BicExampleConfig.SetScanningFitBoxConfiguration(CBicExampleConfig::FIT_BOX_STYLE_MIN_SIZE, 64, 128);
				BicDetector.Scan_SampleMargin	=	Scan_PixelSampleMargin_Test;
				BicDetector.Scan_SampleRate		=	Scan_PixelSampleRate_Test;
				BicDetector.Scan_ScalingFactor	=	Scan_ScalingFactor_Test;
				BicDetector.MeanShiftConfig.KernelConfig.dx = BicDetector.Scan_SampleMargin + 1.0;
				BicDetector.MeanShiftConfig.KernelConfig.dy = BicDetector.Scan_SampleMargin + 1.0;
				BicDetector.MeanShiftConfig.KernelConfig.dw = 1.3;
				BicDetector.MeanShiftConfig.KernelConfig.dw = 1.3;
				BicDetector.SetConfidenceThreshold(Target_CT);

				CSimpleTypeArray<CCandidateDetection> CanDetList;
				CDetectionWithScore tDetetionWithScore;
				CSimpleTypeArray<CDetectionWithScore> MyDetList;
				CSimpleTypeArray<CDetectionWithScore> GtDetList;

				for ( sgnImageSet = 0; sgnImageSet < 2; ++ sgnImageSet )
				{
					if (sgnImageSet==0 && !(BoostDetect_Target_ImageSet & 1)) continue;
					if (sgnImageSet==1 && !(BoostDetect_Target_ImageSet & 2)) continue;

					CExternalTools::ConsoleTools::MakeDirectory(EnvVar.GetPN_BoostDetectOutput_DetectImage(sgnImageSet, 1), true);
					CExternalTools::ConsoleTools::MakeDirectory(EnvVar.GetPN_BoostDetectOutput_DetectImage(sgnImageSet, 0), true);

					tTimer.Reset();
					bcrc.Clear();

					count_image = 0;
					sprintf_s(strTemp, "\n=== Set [%s] ===", EnvVar.GetText_ImageSet(sgnImageSet));
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);

					for ( sgnPosNeg = 1; sgnPosNeg >= 0; -- sgnPosNeg )
					{
						if (sgnPosNeg==1 && !(BoostDetect_Target_PosNeg & 1)) continue;
						if (sgnPosNeg==0 && !(BoostDetect_Target_PosNeg & 2)) continue;

						const CNewBoostSrcImageList& src_sil = EnvVar.GetSIL_SrcImage(sgnImageSet, sgnPosNeg);

						ip_GTL = 0;
						for ( i_image = 0; i_image < src_sil.Amount_SrcImage; ++i_image )
						{
							CExternalTools::myLoadImage(src_sil.GetFN_SrcImage(i_image), imgSrc);
							BicDetector.SetImage(imgSrc);
							const CZoomableImage& ZoomImage_SrcImage = BicDetector.pIPPFE->ZoomImage;
							CZoomConfig ZoomConfig_SrcImage;

							CanDetList.Clear();
							MyDetList.Clear();
							GtDetList.Clear();

							for ( ; ip_GTL < src_sil.Amount_GT_Total; ++ip_GTL )
							{
								const CNewBoostGroundTruthLabel& gtl = src_sil.GT_LabelList.pElement[ip_GTL];
								if (gtl.image_index < i_image) continue;
								if (gtl.image_index > i_image) break;
								tDetetionWithScore.Detection.myInit(gtl.box);
								tDetetionWithScore.Score = 0.0;
								tDetetionWithScore.fIsMatched = false;
								GtDetList.PushBack(tDetetionWithScore);
							} // ip_GTL

							tTimer.Start();
							for ( i_layer = 0; ; ++i_layer )
							{
								int qq = BicDetector.ProcessImageLayer(LayerResult, i_layer, true);
								if (qq < 1) break;

								if (Op_BoostDetect & 1)
								{
									CanDetList.PushBack(LayerResult.CanDetList);
								} // (Op_BoostDetect & 1)
							} // i_layer
							tTimer.Stop();
							++count_image;

							if (Op_BoostDetect & 1)
							{
								ZoomConfig_SrcImage = ZoomImage_SrcImage.BuildImage(imgOutput, OutputScale_1, OutputScale_1, CDenseImage::EXPANDING_MODE_EDGE);
								for ( i_GT = 0; i_GT < (int)GtDetList.Size; ++i_GT )
								{
									ZoomConfig_SrcImage.WorkOnBox(tBox, GtDetList.pElement[i_GT].Detection);
									_color = 0x00ffff00;
									CExternalTools::DrawRectBox(imgOutput, tBox, _color);
								} // i_GT

								BicDetector.DoNMS(MyDetList, CanDetList, true);
								bcrc.ExtraFalseNegAmount += CDetectionWithScore::CheckDetections(MyDetList, GtDetList);
								for ( i_example = 0; i_example < (int)MyDetList.Size; ++i_example )
								{
									tDetetionWithScore = MyDetList.pElement[i_example];
									(tDetetionWithScore.fIsMatched ? bcrc.Pos : bcrc.Neg).PushBack(tDetetionWithScore.Score);

									ZoomConfig_SrcImage.WorkOnBox(tBox, tDetetionWithScore.Detection);
									_color = (tDetetionWithScore.fIsMatched ? 0x0000ff00 : 0x00ff0000);
									CExternalTools::DrawRectBox(imgOutput, tBox, _color);

									sprintf_s(strTemp, "%+.4lf", tDetetionWithScore.Score); // 0.0 - log(exp(0.0 - tDetetionWithScore.Score) - 1.0));
									CExternalTools::OutputTextToImage(imgOutput, strTemp,
										(int)tBox.x, (int)tBox.y,
										((_color>>16)&255), ((_color>>8)&255), ((_color>>0)&255),
										0, 0, 0);
								} // i_example

								bcrc.Analyse();
								double CurrentAP = bcrc.Get_AveragePrecision();

								sprintf_s(strTemp, "Current AP = %.2lf%%", CurrentAP * 100.0);
								CExternalTools::OutputTextToImage(imgOutput, strTemp, 0, 0, 255, 255, 255, 0, 0, 0);

								CExternalTools::mySaveImage(EnvVar.GetFN_BoostDetectOutput_DetectImage(sgnImageSet, sgnPosNeg, i_image), imgOutput);

								sprintf_s(strTemp, "Detect Image [%s] [%d/%d], [%s] per image, AP = %.2lf%%;",
									EnvVar.GetText_PosNeg(sgnPosNeg),
									i_image+1, src_sil.Amount_SrcImage,
									CExternalTools::GetTimeText(tTimer.GetCumulativeTime()/count_image),
									CurrentAP * 100.0);
								CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, false);
								//CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
							} // (Op_BoostDetect & 1)
						} // i_image
					} // sgnPosNeg

					if (Op_BoostDetect & 1)
					{
						bcrc.Analyse();
						double FinalAP = bcrc.Get_AveragePrecision();
						sprintf_s(strTemp, "Detection Finished [%d], [%s] per image, AP = %.2lf%%;",
							count_image,
							CExternalTools::GetTimeText(tTimer.GetCumulativeTime()/count_image),
							FinalAP * 100.0);
						CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
						CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);

						bcrc.Analyse();
						ofstream outFile(EnvVar.GetFN_BoostDetectPRC().c_str());
						bcrc.OutputPRCtoStream(outFile, 100, 0.0, 1.0, false);
						outFile.clear();
						outFile.close();
					} // (Op_BoostDetect & 1)

				} // sgnImageSet

				CDataStructureTools::MyRelease_Single(pIPPFE);
			} // (Op_BoostDetect & 1)

			int BA_Hist_BinAmount = 8;
			int BA_CelPix_WH = 4;
			int BA_Draw_CelPix_WH = 24;

			if (Op_BoostAnalyse & 1)
			{
				CWindowGradient wg;
				wg.InitIPPFE(
					FeatureExtractor.IFB_TextonSigma,
					FeatureExtractor.IFB_ImageExtent,
					BA_Hist_BinAmount,
					BA_CelPix_WH, BA_CelPix_WH,
					BicEC.StdObjectContext_W / BA_CelPix_WH,
					BicEC.StdObjectContext_H / BA_CelPix_WH);
				wg.InitDataSet(
					&EnvVar.pfsl_Train,
					EnvVar.GetFN_BicExampleList(0), false
					);

				CDataSetForBinaryClassification bcDS;
				CBinaryClassificationExampleList bcEL;
				bcDS.SetRealDataSet(&wg.RealDataSet);
				bcDS.SetTargetLabel(+1);
				bcEL.myInit(&bcDS);

				CImg<int> imgOutput;
				CSimpleTypeArray<double> vf;
				CSimpleTypeArray<double> tvf;

				int i_feature;
				int nPos, nNeg;
				CWeightedClassificationExample tExample;
				CWeightedClassificationExampleList PosExampleList;
				CWeightedClassificationExampleList NegExampleList;

				vf.Resize(wg.FeatureDimension);
				vf.Fill(0.0);

				PosExampleList.Clear();
				nPos = 0;
				for ( i_example = 0; i_example < bcEL.PosList.ExampleAmount; ++i_example )
				{
					//if (CMyRandom::NextInt(100) > 0) continue;
					++nPos;
					tExample.ExampleIndex = bcEL.PosList.rgExample[i_example].ExampleIndex;
					tExample.Weight = +1.0;
					PosExampleList.PushBack(tExample);
				}
				sprintf_s(strTemp, "#.Pos = [%d];", nPos);
				CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
				CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
				wg.AverageGradient(tvf, PosExampleList);
				for ( i_feature = 0; i_feature < wg.FeatureDimension; ++i_feature )
					vf.pElement[i_feature] += tvf.pElement[i_feature] / nPos;

				wg.DrawGradientImage(imgOutput, BA_Draw_CelPix_WH, BA_Draw_CelPix_WH, tvf.pElement);
				//CExternalTools::mySaveImage("PosSet.jpg", imgOutput);

				NegExampleList.Clear();
				nNeg = 0;
				for ( i_example = 0; i_example < bcEL.NegList.ExampleAmount; ++i_example )
				{
					if (CMyRandom::NextInt(1000) > 0) continue;
					++nNeg;
					tExample.ExampleIndex = bcEL.NegList.rgExample[i_example].ExampleIndex;
					tExample.Weight = -1.0;
					NegExampleList.PushBack(tExample);
				}
				sprintf_s(strTemp, "#.Neg = [%d];", nNeg);
				CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
				CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
				wg.AverageGradient(tvf, NegExampleList);
				for ( i_feature = 0; i_feature < wg.FeatureDimension; ++i_feature )
					vf.pElement[i_feature] += tvf.pElement[i_feature] / nNeg;

				wg.DrawGradientImage(imgOutput, BA_Draw_CelPix_WH, BA_Draw_CelPix_WH, tvf.pElement);
				//CExternalTools::mySaveImage("NegSet.jpg", imgOutput);

				wg.DrawGradientImage(imgOutput, BA_Draw_CelPix_WH, BA_Draw_CelPix_WH, vf.pElement);
				//CExternalTools::mySaveImage("TargetConcept.jpg", imgOutput);

				sprintf_s(strTemp, "Finished Drawing Window Average Gradient;");
				CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
				CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
			} // (Op_BoostAnalyse & 1)

			if (Op_BoostAnalyse & 2)
			{
				CCascadedAdaBoostClassifier cabc;
				cabc.LoadFromFile(EnvVar.GetFN_BoostModel());

				CWindowGradient wg;
				wg.InitIPPFE(
					FeatureExtractor.IFB_TextonSigma,
					FeatureExtractor.IFB_ImageExtent,
					BA_Hist_BinAmount,
					BA_CelPix_WH, BA_CelPix_WH,
					BicEC.StdObjectContext_W / BA_CelPix_WH,
					BicEC.StdObjectContext_H / BA_CelPix_WH);

				CImagePyramidPositionFeatureExtractor* pIPPFE = FeatureExtractor.GetIPPFE(1);

				CImg<int> imgOutput;

				sgnImageSet = 1;
				{
					sprintf_s(strTemp, "\n=== Set [%s] ===", EnvVar.GetText_ImageSet(sgnImageSet));
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);

					CBicExampleFeatureDataSet ClassificationDataSet;
					ClassificationDataSet.InitBicExampleParentFileNameSetList(&(sgnImageSet==0 ? EnvVar.pfsl_Train : EnvVar.pfsl_Test), "");
					ClassificationDataSet.InitBicExampleList_Binary(EnvVar.GetFN_BicExampleList(sgnImageSet));
					ClassificationDataSet.InitIPPFE(pIPPFE, true);

					wg.InitDataSet(
						&(sgnImageSet==0 ? EnvVar.pfsl_Train : EnvVar.pfsl_Test),
						EnvVar.GetFN_BicExampleList(sgnImageSet), false);

					CDataSetForBinaryClassification bcDS;
					CBinaryClassificationExampleList bcEL;
					bcDS.SetRealDataSet(&ClassificationDataSet);
					bcDS.SetTargetLabel(+1);
					bcEL.myInit(&bcDS);

					int i_feature;
					CSimpleTypeArray<double> tGFV;
					CSimpleTypeArray<CSimpleTypeArray<double>> PosGFV;
					CSimpleTypeArray<CSimpleTypeArray<double>> NegGFV;
					CSimpleTypeArray<CSimpleTypeArray<double>> FullGFV;

					tGFV.Resize(wg.FeatureDimension); tGFV.Fill(0.0);
					PosGFV.Resize(cabc.LayerAmount + 1); PosGFV.Fill(tGFV);
					NegGFV.Resize(cabc.LayerAmount + 1); NegGFV.Fill(tGFV);
					FullGFV.Resize(cabc.LayerAmount + 1); FullGFV.Fill(tGFV);

					CSimpleTypeArray<CBinaryClassificationExampleList> FilterExampleList;
					FilterExampleList.Resize(cabc.LayerAmount + 1);
					for ( i_layer = 0; i_layer <= cabc.LayerAmount; ++i_layer )
						FilterExampleList.pElement[i_layer].Clear();

					double tConfidence;
					int tPrediction, tExitLayer;
					double PosExampleSampleRate = 1.00;
					double NegExampleSampleRate = 0.20;

					for ( sgnPosNeg = 1; sgnPosNeg >= 0; --sgnPosNeg )
					{
						const CWeightedClassificationExampleList& src_cel = (sgnPosNeg==1 ? bcEL.PosList : bcEL.NegList);
						double CurrentSampleRate = (sgnPosNeg==1 ? PosExampleSampleRate : NegExampleSampleRate);
						for ( i_example = 0; i_example < src_cel.ExampleAmount; ++i_example )
						{
							if (CMyRandom::NextDouble() > CurrentSampleRate) continue;
							const CWeightedClassificationExample& CurrentExample = src_cel.rgExample[i_example];
							cabc.Classify(&ClassificationDataSet, CurrentExample.ExampleIndex, -1, tConfidence, tPrediction, tExitLayer);

							tGFV.Fill(0.0);
							wg.MakeGradientVector(tGFV.pElement, CurrentExample.ExampleIndex, (sgnPosNeg==1 ? +1.0 : -1.0));

							if (tExitLayer > cabc.LayerAmount) tExitLayer = cabc.LayerAmount;
							for ( i_layer = 0; i_layer <= tExitLayer; ++i_layer )
							{
								CBinaryClassificationExampleList& dst_cbcel = FilterExampleList.pElement[i_layer];
								CWeightedClassificationExampleList& dst_cel = (sgnPosNeg==1 ? dst_cbcel.PosList : dst_cbcel.NegList);
								dst_cel.PushBack(CurrentExample);

								const double* QD = tGFV.pElement;
								double* PD = (sgnPosNeg==1 ? PosGFV : NegGFV).pElement[i_layer].pElement;
								for ( i_feature = 0; i_feature < wg.FeatureDimension; ++i_feature )
									PD[i_feature] += QD[i_feature];
							}

							if (CMyRandom::NextInt((int)(src_cel.ExampleAmount * NegExampleSampleRate / 1000.0)) > 0) continue;

							sprintf_s(strTemp, "BA [%s] [%.2lf%%];",
								EnvVar.GetText_PosNeg(sgnPosNeg),
								100.0*(i_example+1)/src_cel.ExampleAmount);
							CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, false);
						}
					}

					for ( i_layer = 0; i_layer <= cabc.LayerAmount; ++i_layer )
					{
						double* PD_Pos = PosGFV.pElement[i_layer].pElement;
						double* PD_Neg = NegGFV.pElement[i_layer].pElement;
						double* PD_Full = FullGFV.pElement[i_layer].pElement;

						double tw_Pos = 1.0 / (FilterExampleList.pElement[i_layer].PosList.ExampleAmount + EPS);
						double tw_Neg = 1.0 / (FilterExampleList.pElement[i_layer].NegList.ExampleAmount + EPS);

						for ( i_feature = 0; i_feature < wg.FeatureDimension; ++i_feature )
						{
							PD_Pos[i_feature] *= tw_Pos;
							PD_Neg[i_feature] *= tw_Neg;
							PD_Full[i_feature] = PD_Pos[i_feature] + PD_Neg[i_feature];
						}

						wg.DrawGradientImage(imgOutput, BA_Draw_CelPix_WH, BA_Draw_CelPix_WH, PD_Pos);
						sprintf_s(strTemp, "%s.Layer.Pos.%d.jpg", EnvVar.GetText_ImageSet(sgnImageSet), i_layer);
						CExternalTools::mySaveImage(strTemp, imgOutput);

						wg.DrawGradientImage(imgOutput, BA_Draw_CelPix_WH, BA_Draw_CelPix_WH, PD_Neg);
						sprintf_s(strTemp, "%s.Layer.Neg.%d.jpg", EnvVar.GetText_ImageSet(sgnImageSet), i_layer);
						CExternalTools::mySaveImage(strTemp, imgOutput);

						wg.DrawGradientImage(imgOutput, BA_Draw_CelPix_WH, BA_Draw_CelPix_WH, PD_Full);
						sprintf_s(strTemp, "%s.Layer.Full.%d.jpg", EnvVar.GetText_ImageSet(sgnImageSet), i_layer);
						CExternalTools::mySaveImage(strTemp, imgOutput);

						sprintf_s(strTemp, "BA Draw Layer [%d/%d], #.P:N = [%d:%d];",
							i_layer, cabc.LayerAmount,
							FilterExampleList.pElement[i_layer].PosList.ExampleAmount,
							FilterExampleList.pElement[i_layer].NegList.ExampleAmount);
						CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
						CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
					}

					sprintf_s(strTemp, "BA Finished;");
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
				} // sgnImageSet

				CDataStructureTools::MyRelease_Single(pIPPFE);
			} // (Op_BoostAnalyse & 2)

			if (Op_BoostAnalyse & 4)
			{
				string strPN_BA_Box = "BA_Box\\";

				CExternalTools::ConsoleTools::MakeDirectory(strPN_BA_Box, true);

				CCascadedAdaBoostClassifier cabc;
				cabc.LoadFromFile(EnvVar.GetFN_BoostModel());
				//cabc.TestLayerAmount = 1;
				CBinaryClassifier* pBC = &cabc;

				CImagePyramidPositionFeatureExtractor* pIPPFE = FeatureExtractor.GetIPPFE(1);

				CBicExample tBicExample;
				CRectBox<double> dBox;
				CImg<int> imgSrc;
				CImg<int> imgOutput;
				CImagePyramidPosition ipp;
				CZoomConfig ZoomConfig;

				sgnImageSet = 0;
				{
					sprintf_s(strTemp, "\n=== Set [%s] ===", EnvVar.GetText_ImageSet(sgnImageSet));
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);

					const CNewBoostSrcImageList& src_sil = EnvVar.GetSIL_SrcImage(sgnImageSet, 1);

					class CTempRecord
					{
					public:
						CImg<int> imgOutput;
						CNewBoostGroundTruthLabel gtl;
						double score;
						int gt_index;
						int f_flipped;

					public:
						static bool BetterByScore(const CTempRecord& a, const CTempRecord& b)
						{
							return a.score > b.score;
						}
					};

					CTempRecord TempRecord;
					CSimpleTypeArray<CTempRecord> ListTR;
					ListTR.Clear();

					int i_difficulty;
					CSimpleTypeArray<CHistogramDistribution> HD3;
					HD3.Resize(3);

					for ( i_difficulty = 0; i_difficulty < 3; ++i_difficulty )
					{
						HD3.pElement[i_difficulty].InitHistogramConfig(20, false,
							-2.5, 0.0);
							//exp(cabc.GetMinConfidenceBound(cabc.TestLayerAmount)),
							//exp(cabc.GetMaxConfidenceBound(cabc.TestLayerAmount)));
					}

					int gt_count = 0;
					int last_image_index = -1;
					for ( i_image = 0; i_image < src_sil.Amount_GT_Total; ++i_image )
					{
						const CNewBoostGroundTruthLabel& gtl = src_sil.GT_LabelList.pElement[i_image];

						if (last_image_index != gtl.image_index)
						{
							last_image_index = gtl.image_index;
							CExternalTools::myLoadImage(src_sil.GetFN_SrcImage(last_image_index), imgSrc);
							pIPPFE->SetImage(imgSrc, "");
						}

						dBox.myInit(gtl.box);
						BicEC.MakeContextBoxFromTightBox(dBox, dBox);
						BicEC.MakeExampleFromContextBox(tBicExample, dBox);
						double tConfidence;
#if 1
						ZoomConfig.myInit(
							tBicExample.ipl_scale_x * 2.0,
							tBicExample.ipl_scale_y * 2.0,
							dBox.x, dBox.y, 0, 0);
						int iw = CMyMath::TranslateNumber_Round(dBox.w * tBicExample.ipl_scale_x * 2.0, (int)0);
						int ih = CMyMath::TranslateNumber_Round(dBox.h * tBicExample.ipl_scale_y * 2.0, (int)0);
						pIPPFE->ZoomImage.BuildImage(imgOutput, iw, ih, ZoomConfig, CDenseImage::EXPANDING_MODE_EDGE);

						tBicExample.ToIpp(ipp);

						for ( int i_flipped = 0; i_flipped <= 0; ++i_flipped )
						//for ( int i_flipped = 0; i_flipped <= 1; ++i_flipped )
						{
							if (i_flipped == 1)
								ipp.InitNew(ipp.xOld, ipp.yOld, -ipp.xScale, ipp.yScale);
							pIPPFE->SetQuery(ipp);
							tConfidence = pBC->Classify(pIPPFE);

							sprintf_s(strTemp, "%+9.6lf, %d", tConfidence, gtl.difficulty);
							CExternalTools::OutputTextToImage(imgOutput, strTemp, 0, 0, 0, 0, 0,
								(gtl.difficulty==1 ? 0 : 255),
								(gtl.difficulty==2 ? 0 : 255),
								0, 10);
							sprintf_s(strTemp, "%04d, %d/%d/%d",
								gt_count, gtl.image_index, gtl.object_index, i_flipped);
							CExternalTools::OutputTextToImage(imgOutput, strTemp, 0, 10, 0, 0, 0,
								(gtl.difficulty==1 ? 0 : 255),
								(gtl.difficulty==2 ? 0 : 255),
								0, 10);

							HD3.pElement[gtl.difficulty].NewWeightedValue(tConfidence);
							//HD3.pElement[gtl.difficulty].NewWeightedValue(exp(tConfidence));

							TempRecord.gtl = gtl;
							TempRecord.score = tConfidence;
							TempRecord.imgOutput = imgOutput;
							TempRecord.gt_index = gt_count;
							TempRecord.f_flipped = i_flipped;
							ListTR.PushBack(TempRecord);

							++gt_count;

							sprintf_s(strTemp, "%04d\t%d\t%+9.6lf\t%d\t%d\t%d",
								TempRecord.gt_index, TempRecord.gtl.difficulty, TempRecord.score,
								TempRecord.gtl.image_index, TempRecord.gtl.object_index, TempRecord.f_flipped);
							CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);

							sprintf_s(strTemp, "BA Box [%d/%d];",
								i_image+1, src_sil.Amount_GT_Total);
							CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, false);
						}
					} // i_image

					std::sort(ListTR.Begin(), ListTR.End(), CTempRecord::BetterByScore);

					// Analyse Score Distribution
					{
						int i_bin;
						CSimpleTypeArray<double> xl;
						CSimpleTypeArray<double> yl_0;
						CSimpleTypeArray<double> yl_1;
						CSimpleTypeArray<double> yl_2;
						HD3.pElement[0].Analyse(xl, yl_0);
						HD3.pElement[1].Analyse(xl, yl_1);
						HD3.pElement[2].Analyse(xl, yl_2);

						CExternalTools::ConsoleTools::OutputTextToStream(outLog, "", true);
						for ( i_bin = 0; i_bin < (int)xl.Size; ++i_bin )
						{
							sprintf_s(strTemp, "%+9.6lf\t%6.4lf\t%6.4lf\t%6.4lf",
								xl.pElement[i_bin],
								yl_0.pElement[i_bin],
								yl_1.pElement[i_bin],
								yl_2.pElement[i_bin]);
							CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
						} // i_bin
						CExternalTools::ConsoleTools::OutputTextToStream(outLog, "", true);
					} // Analyse Score Distribution

					for ( i_image = 0; i_image < (int)ListTR.Size; ++i_image )
					{
						CTempRecord& ttr = ListTR.pElement[i_image];
						sprintf_s(strTemp, "%s%s.%04d.%d.%04d.%d.%d.jpg",
							strPN_BA_Box.c_str(), EnvVar.GetText_ImageSet(sgnImageSet),
							i_image, ttr.gtl.difficulty, ttr.gt_index, ttr.gtl.image_index, ttr.gtl.object_index);
						CExternalTools::mySaveImage(strTemp, ttr.imgOutput);
					} // i_image

					sprintf_s(strTemp, "BA Box Finished;");
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
#else
						//double dx, dy, ds;
						//double BestConfidence;

						//int draw_extent = 0;
						//double dx_range = dBox.w * 0.125;
						//double dy_range = dBox.h * 0.125;
						//double ds_range = log(Scan_ScalingFactor_Train) * 1.0;

						//dBox.x += dBox.w * 0.5;
						//dBox.y += dBox.h * 0.5;
						//dBox.w *= exp(ds_range);
						//dBox.h *= exp(ds_range);
						//dBox.w += dx_range + dx_range;
						//dBox.h += dy_range + dy_range;
						//dBox.x -= dBox.w * 0.5;
						//dBox.y -= dBox.h * 0.5;
						//ZoomConfig.myInit(
						//	tBicExample.ipl_scale_x, tBicExample.ipl_scale_y,
						//	dBox.x, dBox.y,
						//	draw_extent, draw_extent);
						//int iw = CMyMath::TranslateNumber_Round(dBox.w * tBicExample.ipl_scale_x, (int)0) + draw_extent * 2;
						//int ih = CMyMath::TranslateNumber_Round(dBox.h * tBicExample.ipl_scale_y, (int)0) + draw_extent * 2;
						//pIPPFE->ZoomImage.BuildImage(imgOutput, iw, ih, ZoomConfig, CDenseImage::EXPANDING_MODE_EDGE);

						//BicEC.MakeContextBoxFromExample(dBox, tBicExample);
						//ZoomConfig.WorkOnBox(dBox, dBox);
						//CExternalTools::DrawRectBox(imgOutput, dBox, 0x00ffff00);

						////CExternalTools::mySaveImage("a.jpg", imgOutput);

						//BestConfidence = -MAXIMUM_DOUBLE_NUM_V;
						//for ( i_example = 0; i_example < 100; ++i_example )
						//{
						//	tBicExample.ToIpp(ipp);

						//	dx = (CMyRandom::NextDouble() * 2.0 - 1.0);
						//	dy = (CMyRandom::NextDouble() * 2.0 - 1.0);
						//	ds = (CMyRandom::NextDouble() * 2.0 - 1.0);

						//	if (i_example == 0)
						//		dx = dy = ds = 0.0;

						//	dx *= dx_range;
						//	dy *= dy_range;
						//	ds *= ds_range;
						//	ds = exp(ds);

						//	dx += ipp.xOld;
						//	dy += ipp.yOld;
						//	ds *= sqrt(ipp.xScale * ipp.yScale);

						//	ipp.InitNew(dx, dy, ds, ds);
						//	pIPPFE->SetQuery(ipp);

						//	tConfidence = pBC->Classify(pIPPFE);
						//	if (tConfidence < BestConfidence) continue;

						//	BestConfidence = tConfidence;
						//	BicEC.MakeContextBoxFromCenterAndIplScale(dBox, dx, dy, ds);
						//}

						//ZoomConfig.WorkOnBox(dBox, dBox);
						//CExternalTools::DrawRectBox(imgOutput, dBox, 0x00ff0000);
						//sprintf_s(strTemp, "%s%s.%04d.jpg",
						//	strPN_BA_Box.c_str(),
						//	EnvVar.GetText_ImageSet(sgnImageSet),
						//	i_image);
						//CExternalTools::mySaveImage(strTemp, imgOutput);

						//sprintf_s(strTemp, "BA Fix Box [%d/%d];",
						//	i_image+1, src_sil.Amount_GT_Total);
						//CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, false);
					//} // i_image
					//sprintf_s(strTemp, "BA Fix Box Finished;");
					//CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					//CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
#endif
				} // sgnImageSet

				CDataStructureTools::MyRelease_Single(pIPPFE);
			} // (Op_BoostAnalyse & 4)

		} // Main Code

		CExternalTools::ConsoleTools::MakeCurrentLine("", true);
		CExternalTools::ConsoleTools::OutputTextToStream(outLog, "", true);
		outLog.close();
		outLog.clear();
	}

	CImageEx::Release();
	return 0;
}

